package com.aric.springbootmusic.utils;


import com.aric.springbootmusic.exceptions.FileContentTypeMismatchException;
import com.aric.springbootmusic.exceptions.TimeException;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.catalina.util.URLEncoder;
import org.apache.tomcat.util.codec.binary.Base64;
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

public class FileHandleUtil {

    /**
     * 判断文件是否超过限制的大小
     * @param file 上传的文件
     * @param limitSize 限制的大小
     */
    public static boolean isOverLimitSize(MultipartFile file,long limitSize) throws FileSizeLimitExceededException {
        long size = file.getSize();//单位字节(b)
        long fileSize=size/(1024*1024);

        if(fileSize>limitSize){
            //抛出异常
            throw new FileSizeLimitExceededException("文件大小超过"+limitSize+"M限制了",fileSize,limitSize);
        }
        return true;
    }

    /**
     * 判断文件内容类型是否符合限制的类型
     * @param limitFileTypeArr 自定义文件内容类型数组
     * @param fileContentType 真实的文件内容类型
     * @return
     */
    public static boolean isMatchLimitFileContentType(String[] limitFileTypeArr,String fileContentType) throws FileContentTypeMismatchException {
        if(!Arrays.asList(limitFileTypeArr).contains(fileContentType)){
            throw new FileContentTypeMismatchException("文件内容类型不符合限制的"+limitFileTypeArr.toString()+"要求");
        }
        return true;
    }

    /**
     * 获取一个字符串类型的时间
     * @param seconds 秒
     * @return
     */
    public static String formatTime(int seconds) throws TimeException {
        //判断时间大于0
        if(seconds<=0){
            //抛出异常
            throw new TimeException("时间必须大于0");
        }

        String time="";
        int minute= seconds / 60;
        int second= seconds % 60;

        //小于1分钟
        if(minute==0){
            if(second<10){
                 time+=("00:0"+second);
            }else {
                time+=("00:"+second);
            }
        }else if(minute<10){
            if(second<10){
                time+=("0"+minute+":0"+second);
            }else {
                time+=("0"+minute+":"+second);
            }
        }else {
            if(second<10){
                time+=(minute+":0"+second);
            }else {
                time+=(minute+":"+second);
            }
        }
        return time;
    }

    /**
     * 获取音频文件的信息
     * @param urlMap  音频文件
     * @param fileContentType 音频文件内容类型
     * @return 返回一个map集合
     * totalTime       时长
     * format          制作格式/制作技巧
     * title           歌名
     * artist          歌手
     * lyricist        作词
     * composer        谱曲
     * arranger        编曲
     * tempo           节奏
     * remixer         混音
     * album           专辑
     * albumArtist     专辑艺人
     * releaseDate     发行日期
     * releaseCountry  发行国家
     */
    public static Map<String,String>  getAudioInfo(Map<String,String> urlMap,String fileContentType) throws CannotReadException, TagException, InvalidAudioFrameException, ReadOnlyFileException, IOException, TimeException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, InvalidKeyException {
        Map<String,String> map=new HashMap<>();
        //将urlMap里的值逐个添加到map里,需要判断，取出来值
        AtomicReference<String> realUrl = new AtomicReference<>("");
        Set<String> keySet = urlMap.keySet();
        keySet.forEach(key->{
            if(urlMap.get(key).indexOf("http")==-1 && urlMap.get(key).indexOf("https")==-1){
                realUrl.set(urlMap.get(key));
            }
            map.put(key,urlMap.get(key));
        });

        //获取密文
        String secret=realUrl.get();
        //获取密钥
        String privateKey = SecretKey.getPrivateKey();
        //使用RSA解密
        String realPath = RSAEncryptUtil.decrypt(secret, Base64.decodeBase64(privateKey));
        File file=new File(realPath);
        AudioFile audioFile= AudioFileIO.read(file);
        //获取总时间
        String time=formatTime(audioFile.getAudioHeader().getTrackLength());
        map.put("totalTime",time);
        //格式
        String format = audioFile.getAudioHeader().getFormat();
        map.put("format",format);
        //tag不为空的情况下
        if(Objects.nonNull(audioFile.getTag())){
            Tag tag=audioFile.getTag();
            //歌名
            String title=tag.getFirst(FieldKey.TITLE);
            map.put("songName",title);
            //歌手
            String artist=tag.getFirst(FieldKey.ARTIST);
            map.put("singer",artist);

            if(fileContentType.equals("audio/wav")){
                //作词
                map.put("lyricist","");
                //谱曲
                map.put("composer","");
                //编曲
                map.put("arranger","");
                //节奏
                map.put("tempo","");
                //混音
                map.put("remixer","");
                //专辑
                map.put("album","");
                //专辑艺人
                map.put("albumArtist","");
                //发行日期
                map.put("releaseDate","");
                //发行国家
                map.put("releaseCountry","");
            }else {
                //作词
                String lyricist  = tag.getFirst(FieldKey.LYRICIST);
                map.put("lyricist",lyricist);
                //谱曲
                String composer  = tag.getFirst(FieldKey.COMPOSER);
                map.put("composer",composer);
                //编曲
                String arranger  = tag.getFirst(FieldKey.ARRANGER);
                map.put("arranger",arranger);
                //节奏
                String tempo  = tag.getFirst(FieldKey.TEMPO);
                map.put("tempo",tempo);
                //混音
                String remixer  = tag.getFirst(FieldKey.REMIXER);
                map.put("remixer",remixer);
                //专辑
                String album  = tag.getFirst(FieldKey.ALBUM);
                map.put("album",album);
                //专辑艺人
                String album_artist  = tag.getFirst(FieldKey.ALBUM_ARTIST);
                map.put("albumArtist",album_artist);
                //发行日期
                String releaseDate  = tag.getFirst(FieldKey.YEAR);
                map.put("releaseDate",releaseDate);
                //发行国家
                String releaseCountry  = tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY);
                map.put("releaseCountry",releaseCountry);
            }

            if(fileContentType.equals("audio/mpeg")){
                //版权
                map.put("copyright","");
            }else {
                String copyright="";
                if(tag.hasField("COPYRIGHT")){
                    copyright = tag.getFirst("COPYRIGHT");
                }
                map.put("copyright",copyright);
            }
        }else {
            //歌名
            map.put("title","");
            //歌手
            map.put("artist","");
            //作词
            map.put("lyricist","");
            //谱曲
            map.put("composer","");
            //编曲
            map.put("arranger","");
            //节奏
            map.put("tempo","");
            //混音
            map.put("remixer","");
            //专辑
            map.put("album","");
            //专辑艺人
            map.put("albumArtist","");
            //发行日期
            map.put("releaseDate","");
            //发行国家
            map.put("releaseCountry","");
            //版权
            map.put("copyright","");
        }
        return map;
    }

    /**
     * 下载音频文件
     * @param url
     * @param response
     */
    public static void downloadAudioFile(String url,HttpServletResponse response) throws IOException {
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;");
        OutputStream os = new BufferedOutputStream(response.getOutputStream());
        URL urlFile=new URL(url);
        InputStream in = urlFile.openStream();
        in.transferTo(os);
        os.close();
        in.close();
    }

    /**
     * 上传文件
     * @param file
     * @param httpBaseUrl
     * @param realBaseUrl
     * @return
     * @throws IOException
     */
    public static Map<String,String> uploadFile(MultipartFile file,String httpBaseUrl,String realBaseUrl) throws IOException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, InvalidKeyException {
        String name= file.getOriginalFilename();
        //文件后缀名
        String ext=name.substring(name.lastIndexOf(".")+1);
        //生成新的文件名
        String fileName = UUID.randomUUID() +"."+ext;

        String url=httpBaseUrl+fileName;

        String toPath=realBaseUrl+fileName;

        File destFile=new File(toPath);
        if(!destFile.exists()){
            destFile.mkdirs();
        }
        //上传
        file.transferTo(destFile);

        //获取公钥
        String publicKey = SecretKey.getPublicKey();
        //使用RSA算法加密
        toPath = RSAEncryptUtil.encrypt(toPath, Base64.decodeBase64(publicKey));

        Map<String,String> map=new HashMap<>();
        //这里需要修改一下，不能使用这种方式,参数太多了，容易忘掉
        if((url.indexOf("http")!=-1 && url.indexOf("audio")!=-1) || (url.indexOf("https")!=-1 && url.indexOf("audio")!=-1)){
            map.put("songAddress",url);
            map.put("songRealAddress",toPath);
        }else{
            map.put("picAddress",url);
            map.put("picRealAddress",toPath);
        }
        return map;
    }
}
